package com.kakarote.examine.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson.JSON;
import com.kakarote.core.entity.UserInfo;
import com.kakarote.core.feign.admin.entity.AdminMessageBO;
import com.kakarote.core.feign.admin.entity.AdminMessageEnum;
import com.kakarote.core.feign.admin.entity.SimpleUser;
import com.kakarote.core.feign.admin.service.AdminMessageService;
import com.kakarote.core.feign.admin.service.AdminService;
import com.kakarote.core.feign.examine.entity.ExamineDataSaveBO;
import com.kakarote.core.feign.examine.entity.ExamineFlowFinalUser;
import com.kakarote.core.feign.examine.entity.ExamineFlowVO;
import com.kakarote.core.servlet.ApplicationContextHolder;
import com.kakarote.core.servlet.BaseServiceImpl;
import com.kakarote.core.utils.UserCacheUtil;
import com.kakarote.core.utils.UserUtil;
import com.kakarote.examine.constant.ExamineStatusEnum;
import com.kakarote.examine.constant.ExamineTypeEnum;
import com.kakarote.examine.entity.BO.ExaminePassBO;
import com.kakarote.examine.entity.PO.*;
import com.kakarote.examine.mapper.ExamineFlowCopyMapper;
import com.kakarote.examine.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 流程抄送节点配置 服务实现类
 * </p>
 *
 * @author zyl
 * @since 2022-08-31
 */
@Service("copyService")
public class ExamineFlowCopyServiceImpl extends BaseServiceImpl<ExamineFlowCopyMapper, ExamineFlowCopy> implements IExamineFlowCopyService, ExamineTypeService {

    @Autowired
    private IExamineRecordLogService examineRecordLogService;
    @Autowired
    private AdminService adminService;

    @Autowired
    private IExamineFlowFinalOptionalService examineFlowFinalOptionalService;

    @Autowired
    private IExamineFlowFinalService examineFlowFinalService;


    @Autowired
    private IExamineRecordService examineRecordService;

    @Autowired
    private IExamineService examineService;

    @Autowired
    private IExamineFlowService examineFlowService;


    @Override
    public void saveExamineFlowData(ExamineDataSaveBO dataSaveBO, Long flowId, String batchId) {
        ExamineFlowCopy examineFlowCopy = new ExamineFlowCopy();
        examineFlowCopy.setIsAdd(dataSaveBO.getIsAdd());
        examineFlowCopy.setIsSelf(dataSaveBO.getIsSelf());
        examineFlowCopy.setUserIds(JSON.toJSONString(dataSaveBO.getUserList()));
        examineFlowCopy.setRoleIds(JSON.toJSONString(dataSaveBO.getRoleIdList()));
        examineFlowCopy.setParentLevels(JSON.toJSONString(dataSaveBO.getParentLevelList()));
        examineFlowCopy.setFlowId(flowId);
        examineFlowCopy.setCreateTime(DateUtil.date());
        examineFlowCopy.setBatchId(batchId);
        save(examineFlowCopy);
    }


    @Override
    public void queryFlowListByBatchId(Map<String, Object> map, String batchId) {
        List<ExamineFlowCopy> copyFlowList = lambdaQuery().eq(ExamineFlowCopy::getBatchId, batchId).list();
        Map<Long, List<ExamineFlowCopy>> collect = copyFlowList.stream().collect(Collectors.groupingBy(ExamineFlowCopy::getFlowId));
        map.put(ExamineTypeEnum.COPY.getServerName(), collect);
    }

    @Override
    public ExamineFlowVO createFlowInfo(ExamineFlow examineFlow, Map<String, Object> map, List<UserInfo> allUserList, Long ownerUserId) {
        Map<Long, List<ExamineFlowCopy>> collect = (Map<Long, List<ExamineFlowCopy>>) map.get(ExamineTypeEnum.COPY.getServerName());
        List<ExamineFlowCopy> flowCopyList = collect.get(examineFlow.getFlowId());
        if (flowCopyList == null || flowCopyList.size() == 0) {
            return null;
        }
        ExamineFlowCopy examineFlowCopy = flowCopyList.get(0);
        ExamineFlowVO examineFlowVO = new ExamineFlowVO();
        examineFlowVO.setName(examineFlow.getName());
        examineFlowVO.setExamineType(examineFlow.getExamineType());
        examineFlowVO.setFlowId(examineFlow.getFlowId());
        examineFlowVO.setExamineErrorHandling(examineFlow.getExamineErrorHandling());
        examineFlowVO.setIsAdd(examineFlowCopy.getIsAdd());
        examineFlowVO.setIsSelf(examineFlowCopy.getIsSelf());
        String parentLevels = examineFlowCopy.getParentLevels();
        if (StringUtils.isNotEmpty(parentLevels) && !parentLevels.equals("null")) {
            List<Integer> parentLevelList = JSON.parseArray(parentLevels, Integer.class);
            examineFlowVO.setParentLevelList(parentLevelList);
        }
        String optionalUsers = examineFlowCopy.getUserIds();
        if (StringUtils.isNotEmpty(optionalUsers) && !optionalUsers.equals("null")) {
            List<Long> optionalUserList = JSON.parseArray(optionalUsers, Long.class);
            examineFlowVO.setOptionalUserList(optionalUserList);
        }

        String roleIds = examineFlowCopy.getRoleIds();
        if (StringUtils.isNotEmpty(roleIds)) {
            List<Long> roleIdList = JSON.parseArray(roleIds, Long.class);
            if (CollectionUtil.isNotEmpty(roleIdList)) {
                List<Map<String, Object>> roleList = adminService.listByRoleId(roleIdList).getData();
                examineFlowVO.setRoleIdList(roleIdList);
                examineFlowVO.setRoleList(roleList);
            }
        }

        List<SimpleUser> userList = new ArrayList<>();
        List<Long> userIds = queryUserIdList(ownerUserId, examineFlowCopy);
        List<Long> userIdList = handleUserIdList(userIds);
        if (CollectionUtil.isNotEmpty(userIdList)) {
            for (Long userId : userIdList) {
                for (UserInfo userInfo : allUserList) {
                    if (userInfo.getUserId().equals(userId)) {
                        userList.add(toSimPleUser(userInfo));
                        break;
                    }
                }
            }
        }
        examineFlowVO.setUserList(userList);

        return examineFlowVO;
    }


    /**
     * 一级一级向上找到level参数的位置的userId
     *
     * @param userInfos 所有用户list
     * @param userId    userId
     * @param level     等级（限制递归次数）
     * @return 按照等级从低到高排列的userId
     */
    private List<Long> queryParentsSortByLevel(List<UserInfo> userInfos, Long userId, Integer level) {
        List<Long> userIds = new ArrayList<>();
        if (ObjectUtil.equal(0, level)) {
            return userIds;
        }
        if (ObjectUtil.isNotNull(userId) && userId > 0) {
            for (UserInfo user : userInfos) {
                if (ObjectUtil.equal(userId, user.getUserId())) {
                    userIds.add(userId);
                    userIds.addAll(queryParentsSortByLevel(userInfos, user.getParentId(), level - 1));
                }
            }
        }
        return userIds;
    }

    private List<Long> queryUserIdList(Long createUserId, ExamineFlowCopy examineFlowCopy) {
        List<Long> userList = new ArrayList<>();
        if (StringUtils.isNotEmpty(examineFlowCopy.getUserIds())) {
            List<Long> userIds = JSON.parseArray(examineFlowCopy.getUserIds(), Long.class);
            userList.addAll(userIds);
        }
        List<UserInfo> userInfoList = adminService.queryUserInfoList().getData();
        if (StringUtils.isNotEmpty(examineFlowCopy.getRoleIds())) {
            List<Long> roleIds = JSON.parseArray(examineFlowCopy.getRoleIds(), Long.class);
            if (CollectionUtil.isNotEmpty(roleIds)) {
                for (UserInfo userInfo : userInfoList) {
                    if (userInfo.getRoles().contains(roleIds)) {
                        if (!userList.contains(userInfo.getUserId())) {
                            userList.add(userInfo.getUserId());
                        }
                    }
                }
            }
        }
        if (StringUtils.isNotEmpty(examineFlowCopy.getParentLevels())) {
            List<Integer> parentLevelList = JSON.parseArray(examineFlowCopy.getParentLevels(), Integer.class);
            if (CollectionUtil.isNotEmpty(parentLevelList)) {
                parentLevelList.forEach(parentLevel -> {
                    List<Long> parentUserIdList = queryParentsSortByLevel(userInfoList, createUserId, parentLevel);
                    if (CollectionUtil.isNotEmpty(parentUserIdList)) {
                        userList.addAll(parentUserIdList);
                    }
                });
            }
        }
        return userList;
    }

    /**
     * 处理当前节点
     *
     * @param examineFlow 当前处理节点
     * @param recordId    审核记录ID
     * @param data        特殊处理数据
     * @param examine     审核对象
     * @param init        是否初始化
     * @return data
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public JSONObject disposeFlow(ExamineFlow examineFlow, Long recordId, Object data, Examine examine, boolean init) {
        if (examine == null) {
            if (examineFlow.getExamineId().equals(0L)) {
                Long examineId = examineFlowService.lambdaQuery().eq(ExamineFlow::getBatchId, examineFlow.getBatchId()).ne(ExamineFlow::getExamineId, 0).select(ExamineFlow::getExamineId).last("limit 1").one().getExamineId();
                examineFlow.setExamineId(examineId);
            }
            examine = examineService.getById(examineFlow.getExamineId());
        }

        //是否首次处理
        boolean isFirst = true;

        ExamineFlowCopy examineFlowCopy = lambdaQuery().eq(ExamineFlowCopy::getFlowId, examineFlow.getFlowId()).one();

        ExamineFlowFinal examineFlowFinal = examineFlowFinalService.lambdaQuery().eq(ExamineFlowFinal::getRecordId, recordId).eq(ExamineFlowFinal::getFlowId, examineFlow.getFlowId()).eq(ExamineFlowFinal::getExamineId, examineFlow.getExamineId()).one();

        if (examineFlowFinal == null) {
            Integer maxSort = examineFlowFinalService.getMaxSort(recordId, examine.getExamineId());
            examineFlowFinal = new ExamineFlowFinal();
            examineFlowFinal.setName(examineFlow.getName());
            examineFlowFinal.setExamineType(examineFlow.getExamineType());
            examineFlowFinal.setFlowId(examineFlow.getFlowId());
            examineFlowFinal.setExamineErrorHandling(examineFlow.getExamineErrorHandling());
            examineFlowFinal.setCreateTime(new Date());
            examineFlowFinal.setCreateUserId(UserUtil.getUserId());
            examineFlowFinal.setExamineId(examine.getExamineId());
            examineFlowFinal.setRecordId(recordId);
            examineFlowFinal.setType(1);
            examineFlowFinal.setSort(maxSort + 1);
            examineFlowFinalService.save(examineFlowFinal);
        } else {
            isFirst = false;
        }


        List<Long> userList = new ArrayList<>();
        ExamineRecord examineRecord = examineRecordService.getById(recordId);
        //添加发起人抄送
        if (1 == examineFlowCopy.getIsSelf()) {
            if (ObjectUtil.isEmpty(examineRecord)) {
                userList.add(UserUtil.getUserId());
            } else {
                userList.add(examineRecord.getCreateUserId());
            }

        }

        //添加指定人员抄送
        if (ObjectUtil.isNotEmpty(examineFlowCopy.getUserIds())) {
            List<Long> userIds = JSON.parseArray(examineFlowCopy.getUserIds(), Long.class);
            if (CollectionUtil.isNotEmpty(userIds)) {
                userList.addAll(userIds);
            }
        }

        //指定角色抄送
        if (ObjectUtil.isNotEmpty(examineFlowCopy.getRoleIds())) {
            List<Long> roleIds = JSON.parseArray(examineFlowCopy.getRoleIds(), Long.class);
            if (CollectionUtil.isNotEmpty(roleIds)) {
                for (Long roleId : roleIds) {
                    List<Long> userIds = adminService.queryUserIdByRoleId(roleId).getData();
                    if (CollectionUtil.isNotEmpty(userIds)) {
                        userList.addAll(userIds);
                    }
                }
            }
        }


        if (StringUtils.isNotEmpty(examineFlowCopy.getParentLevels())) {
            List<Integer> parentLevelList = JSON.parseArray(examineFlowCopy.getParentLevels(), Integer.class);
            List<UserInfo> userInfoList = adminService.queryUserInfoList().getData();
            if (CollectionUtil.isNotEmpty(parentLevelList)) {
                for (Integer level : parentLevelList) {
                    List<Long> parentUserIdList = queryParentsSortByLevel(userInfoList, examineRecord.getCreateUserId(), level);
                    if (CollectionUtil.isNotEmpty(parentUserIdList)) {
                        userList.addAll(parentUserIdList);
                    }
                }

            }
        }
        //去重
        userList = userList.stream().distinct().collect(Collectors.toList());
        List<ExamineFlowFinalOptional> finalOptionals = new ArrayList<>();
        List<ExamineFlowFinalUser> userListFinal = new ArrayList<>();
        //下标
        int index = 0;

        if (1 == examineFlowCopy.getIsAdd()) {
            if (isFirst) {
                AdminMessageBO adminMessageBO = new AdminMessageBO();
                adminMessageBO.setUserId(UserUtil.getUserId());
                adminMessageBO.setMessageType(AdminMessageEnum.FLOW_OPTIONAL.getType());

                com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
                jsonObject.put("label", examineRecord.getLabel());
                jsonObject.put("typeId", examineRecord.getTypeId() + "");
                adminMessageBO.setContent(jsonObject.toJSONString());

                adminMessageBO.setTitle(examine.getExamineName());
                adminMessageBO.setTypeId(examineRecord.getTypeId());
                adminMessageBO.setIds(Collections.singletonList(examineRecord.getCreateUserId()));
                AdminMessageService messageService = ApplicationContextHolder.getBean(AdminMessageService.class);
                messageService.sendMessage(adminMessageBO);


                return new JSONObject().putOpt("status", ExamineStatusEnum.UNDERWAY.getStatus()).putOpt("examineLogIds", null);
            }
            if (ObjectUtil.isNotEmpty(data)) {
                boolean exists = examineFlowFinalOptionalService.lambdaQuery().eq(ExamineFlowFinalOptional::getRecordId, recordId).eq(ExamineFlowFinalOptional::getFlowId, examineFlow.getFlowId()).exists();
                if (!exists) {
                    for (ExamineFlowFinalUser datum : (List<ExamineFlowFinalUser>) data) {
                        ExamineFlowFinalOptional examineFlowFinalOptional = new ExamineFlowFinalOptional();
                        examineFlowFinalOptional.setCreateTime(new Date());
                        examineFlowFinalOptional.setCreateUserId(UserUtil.getUserId());
                        examineFlowFinalOptional.setFlowId(examineFlow.getFlowId());
                        examineFlowFinalOptional.setRecordId(recordId);
                        examineFlowFinalOptional.setType(1);
                        examineFlowFinalOptional.setSort(index++);
                        examineFlowFinalOptional.setUserId(datum.getUserId());
                        examineFlowFinalOptional.setEmail(datum.getEmail());
                        finalOptionals.add(examineFlowFinalOptional);

                        ExamineFlowFinalUser examineFlowFinalUser = new ExamineFlowFinalUser();
                        examineFlowFinalUser.setUserId(datum.getUserId());
                        examineFlowFinalUser.setEmail(datum.getEmail());
                        userListFinal.add(examineFlowFinalUser);
                    }
                }
            }

        }
        for (Long userId : userList) {
            ExamineFlowFinalOptional examineFlowFinalOptional = new ExamineFlowFinalOptional();
            examineFlowFinalOptional.setCreateTime(new Date());
            examineFlowFinalOptional.setCreateUserId(UserUtil.getUserId());
            examineFlowFinalOptional.setFlowId(examineFlow.getFlowId());
            examineFlowFinalOptional.setRecordId(recordId);
            examineFlowFinalOptional.setType(1);
            examineFlowFinalOptional.setSort(index++);
            examineFlowFinalOptional.setUserId(userId);
            finalOptionals.add(examineFlowFinalOptional);

            ExamineFlowFinalUser examineFlowFinalUser = new ExamineFlowFinalUser();
            examineFlowFinalUser.setUserId(userId);
            userListFinal.add(examineFlowFinalUser);

        }
        ExamineRecordLog examineRecordLog;
        LocalDateTime examineTime = LocalDateTimeUtil.now();
        if (CollectionUtil.isNotEmpty(finalOptionals)) {
            examineFlowFinalOptionalService.saveBatch(finalOptionals);
            List<ExamineRecordLog> recordLogs = examineRecordService.addExamineRecordLogList(examineFlowFinal.getType(), examineFlowFinal.getExamineId(), ExamineStatusEnum.COPY.getStatus(), examineFlowFinal.getFlowId(), examineRecord.getRecordId(), 0, "审批抄送通知", examine.getExamineName(), examineRecord.getTypeId(), null, userListFinal);
            examineTime = recordLogs.stream().findFirst().get().getExamineTime();
            examineRecordLog = recordLogs.get(recordLogs.size() - 1);
        } else {
            examineRecordLog = new ExamineRecordLog();
            examineRecordLog.setFlowId(examineFlow.getFlowId());
            examineRecordLog.setCreateTime(examineTime);
            examineRecordLog.setCreateUserId(UserUtil.getUserId());
            examineRecordLog.setExamineId(examine.getExamineId());
            examineRecordLog.setExamineStatus(ExamineStatusEnum.COPY.getStatus());
            examineRecordLog.setRecordId(examineRecord.getRecordId());
            examineRecordLog.setExamineTime(examineTime);
            examineRecordLog.setSort(0);
            examineRecordLog.setType(1);
            examineRecordLog.setBatchId(IdUtil.simpleUUID());
            examineRecordLog.setRemarks("无抄送人员");
            examineRecordLogService.save(examineRecordLog);
        }
        Long createUserId = examine.getCreateUserId();
        UserInfo userInfo = UserCacheUtil.getUserInfo(createUserId);
        ExaminePassBO examinePassBO = ExaminePassBO.builder().init(init).build();
        if (init) {
            examinePassBO.setDataMap((Map<String, Object>) data);
        }
        Integer examineStatus = examineRecordService.auditExaminePass(examineRecordLog, examineRecord, userInfo, examinePassBO, examineTime);
        return new JSONObject().putOpt("status", examineStatus);
    }

}
